package com.liuyi.framework.web.encrypt;

import cn.hutool.core.util.StrUtil;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.liuyi.tools.SpringContext;
import com.liuyi.tools.kits.RequestKit;
import com.liuyi.tools.web.resp.Response;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.MethodParameter;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;

import javax.annotation.Resource;
import java.io.UnsupportedEncodingException;

/**
 * <p>
 * 加密返回参数
 * </p>
 *
 * @author Mr.Fmy
 * @since 2021-02-01
 */
@Slf4j
@RestControllerAdvice
public class EncryptResponse implements ResponseBodyAdvice<Response<Object>> {

    @Value("${spring.crypto.request.decrypt.charset:UTF-8}")
    private String charset = "UTF-8";
    @Value("${spring.crypto.request.decrypt.key:crypto_decrypt}")
    private String crypto_decrypt = "crypto_decrypt";
    @Value("${spring.crypto.request.decrypt.environment:prd}")
    private String environment = "prd";
    private String active = "";
    @Resource
    private CryptoFilter cryptoFilter;
    @Resource
    private ObjectMapper objectMapper;

    public EncryptResponse() {
        log.info("EncryptResponse init");
    }

    @Override
    public boolean supports(MethodParameter methodParameter, Class<? extends HttpMessageConverter<?>> aClass) {
        if (StrUtil.isBlank(active)) {
            active = SpringContext.getEnv().getProperty("spring.profiles.active");
        }
        if (active.equals(environment)) {
            if (!cryptoFilter.supper() && !cryptoFilter.check(RequestKit.getRequest())) {
                Encrypt methodAnnotation = methodParameter.getMethodAnnotation(Encrypt.class);
                return methodAnnotation != null;
            }
        }
        return false;
    }

    @Override
    public Response<Object> beforeBodyWrite(Response<Object> response, MethodParameter methodParameter, MediaType mediaType, Class<? extends HttpMessageConverter<?>> aClass, ServerHttpRequest serverHttpRequest, ServerHttpResponse serverHttpResponse) {
        Object data = response.getData();
        if (data == null || data instanceof String) {
            return response;
        } else {
            try {
                String resStr = objectMapper.writeValueAsString(data);
                EncryptionTool.Encrypt encrypt = EncryptionTool.encrypt(resStr, charset);
                response.setData(encrypt.getCiphertext());
                serverHttpResponse.getHeaders().add(crypto_decrypt, encrypt.getRsaKey());
                return response;
            } catch (JsonProcessingException | UnsupportedEncodingException e) {
                log.error(e.getMessage(), e);
            }
            return response;
        }
    }
}
